#ifndef __SYLAR_LOG_H__
#define __SYLAR_LOG_H__

#include <string>
#include <stdint.h>
#include <memory>
#include <list>
#include <sstream>

#include <fstream>
#include <vector>
#include <map>
#include <stdarg.h>
#include "util.h"
#include "singleton.h"
#include "mutex.h"
#include "thread.h"


#define SYLAR_LOG_LEVEL(logger, level) \
	if(logger->getLevel() <= level) \
		sylar::LogEventWrap(sylar::LogEvent::ptr(new sylar::LogEvent(logger, level, \
		__FILE__, __LINE__, 0, sylar::GetThreadId(), \
		sylar::GetFiberId(), time(0), sylar::Thread::GetName()))).getSS()


#define SYLAR_LOG_DEBUG(logger) SYLAR_LOG_LEVEL(logger, sylar::LogLevel::DEBUG)
#define SYLAR_LOG_INFO(logger) 	SYLAR_LOG_LEVEL(logger, sylar::LogLevel::INFO)
#define SYLAR_LOG_WARN(logger) 	SYLAR_LOG_LEVEL(logger, sylar::LogLevel::WARN)
#define SYLAR_LOG_ERROR(logger) SYLAR_LOG_LEVEL(logger, sylar::LogLevel::ERROR)
#define SYLAR_LOG_FATAL(logger) SYLAR_LOG_LEVEL(logger, sylar::LogLevel::FATAL)

#define SYLAR_LOG_FMT_LEVEL(logger, level, fmt, ...)\
	if(logger->getLevel() <= level) \
		sylar::LogEventWrap(sylar::LogEvent::ptr( \
		new sylar::LogEvent(logger, level, \
		__FILE__, __LINE__, 0, sylar::GetThreadId(),\
		sylar::GetFiberId(), time(0), sylar::Thread::GetName())\
		)).getEvent()->format(fmt, __VA_ARGS__)

#define SYLAR_LOG_FMT_DEBUG(logger, fmt, ...) 	SYLAR_LOG_FMT_LEVEL(logger, sylar::LogLevel::DEBUG, fmt, __VA_ARGS__)
#define SYLAR_LOG_FMT_INFO(logger, fmt, ...) 	SYLAR_LOG_FMT_LEVEL(logger, sylar::LogLevel::INFO, fmt, __VA_ARGS__)
#define SYLAR_LOG_FMT_WARN(logger, fmt, ...) 	SYLAR_LOG_FMT_LEVEL(logger, sylar::LogLevel::WARN, fmt, __VA_ARGS__)
#define SYLAR_LOG_FMT_ERROR(logger, fmt, ...) 	SYLAR_LOG_FMT_LEVEL(logger, sylar::LogLevel::ERROR, fmt, __VA_ARGS__)
#define SYLAR_LOG_FMT_FATAL(logger, fmt, ...) 	SYLAR_LOG_FMT_LEVEL(logger, sylar::LogLevel::FATAL, fmt, __VA_ARGS__)

#define SYLAR_LOG_ROOT() sylar::LoggerMgr::GetInstance()->getRoot()

#define SYLAR_LOG_NAME(name) sylar::LoggerMgr::GetInstance()->getLogger(name)

namespace sylar
{

class Logger;
class LogFormatter;
class LoggerManager;

// 日志级别
class LogLevel{
public:
	enum Level{
		UNKNOW = 0,
		DEBUG = 1,
		INFO = 2,
		WARN = 3,
		ERROR = 4,
		FATAL = 5
	};

	static std::string to_string(Level Level);
	static LogLevel::Level FromString(const std::string & str);
};

//日志事件
class LogEvent
{
public:
	typedef std::shared_ptr<LogEvent> ptr;
	LogEvent();
	/**
     * @brief 构造函数
     * @param[in] logger 日志器
     * @param[in] level 日志级别
     * @param[in] file 文件名
     * @param[in] line 文件行号
     * @param[in] elapse 程序启动依赖的耗时(毫秒)
     * @param[in] thread_id 线程id
     * @param[in] fiber_id 协程id
     * @param[in] time 日志事件(秒)
     * @param[in] thread_name 线程名称
     */
    LogEvent(std::shared_ptr<Logger> logger, LogLevel::Level level
            ,const char* file, int32_t line, uint32_t elapse
            ,uint32_t thread_id, uint32_t fiber_id, uint64_t time
            ,const std::string& thread_name);

	const char* getFile() const { return m_file; }
	int32_t getLine() const { return m_line; }
	uint32_t getElapse() const { return m_elapse; }
	uint32_t getThreadId() const { return m_threadId; }
	uint32_t getFiberId() const { return m_fiberId; }
	uint64_t getTime() const { return m_time; }
	std::string getThreadName() const { return m_threadName;}
	std::shared_ptr<Logger> getLogger() const { return m_logger;}
	LogLevel::Level getLevel() const { return m_level;}
	std::string getContent() const { return m_ss.str();}
	std::stringstream& getSS() {return m_ss;}
	void format(const char* fmt, ...);
	void format(const char* fmt, va_list al);
private:
	const char* m_file = nullptr;	//文件名
	int32_t m_line = 0;		//行号
	uint32_t m_elapse = 0;		//程序启动开始到现在的毫秒数
	uint32_t m_threadId = 0;	//线程ID
	uint32_t m_fiberId = 0;		//携程ID
	uint64_t m_time;		//时间戳

	std::string m_threadName;
	std::stringstream m_ss;
	std::shared_ptr<Logger> m_logger;
	LogLevel::Level m_level;
};


class LogEventWrap
{
private:
	LogEvent::ptr m_event;
public:
	LogEventWrap(LogEvent::ptr event);
	~LogEventWrap();
	LogEvent::ptr getEvent() const {return m_event;}

	std::stringstream& getSS();
};

//日志格式器
class LogFormatter
{
public:
	typedef std::shared_ptr<LogFormatter> ptr;
	/** 
     *  %m 消息
     *  %p 日志级别
     *  %r 累计毫秒数
     *  %c 日志名称
     *  %t 线程id
     *  %n 换行
     *  %d 时间
     *  %f 文件名
     *  %l 行号
     *  %T 制表符
     *  %F 协程id
     *  %N 线程名称
     *
     *  默认格式 "%d{%Y-%m-%d %H:%M:%S}%T%t%T%N%T%F%T[%p]%T[%c]%T%f:%l%T%m%n"
     */
	LogFormatter(const std::string & pattern);

	std::string format(LogLevel::Level level, std::shared_ptr<Logger> loger, LogEvent::ptr event);
	std::ostream& format(std::ostream& ofs, LogLevel::Level level, std::shared_ptr<Logger> logger, LogEvent::ptr event);
public:
	class FormatItem
	{
	public:
		typedef std::shared_ptr<FormatItem> ptr;
		virtual ~FormatItem(){}
		virtual void format(std::ostream& os, std::shared_ptr<Logger> loger, LogLevel::Level, LogEvent::ptr event) = 0;

	};

	void init();

	bool isError() const{ return m_error;}
	const std::string getPattern() const {return m_pattern;}
private:
	std::string m_pattern;
	std::vector<FormatItem::ptr> m_items;
	// 是否有错误
	bool m_error = false;

};

//日志输出地
class LogAppender
{
friend class Logger;
public:
	typedef std::shared_ptr<LogAppender> ptr;
	typedef Spinlock MutexType;
	
	virtual ~LogAppender(){}

	virtual void log(LogLevel::Level level, std::shared_ptr<Logger> logger, LogEvent::ptr event) = 0;

	void setFormatter(LogFormatter::ptr val);
	LogFormatter::ptr getFormatter();
	void setLevel(LogLevel::Level val){ m_level = val;}
	LogLevel::Level getLevel()const { return m_level;}

	virtual std::string toYamlString() = 0;
protected:
	LogLevel::Level m_level = LogLevel::DEBUG;
	LogFormatter::ptr m_formatter;
	bool m_hasFormatter = false;
	
	MutexType m_mutex;
};

//日志器
class Logger : public std::enable_shared_from_this<Logger>
{
	friend class LoggerManager;
public:
	typedef std::shared_ptr<Logger> ptr;
	typedef Spinlock MutexType;

	Logger(const std::string& name = "root");
	void log(LogLevel::Level level, LogEvent::ptr event);

	void debug(LogEvent::ptr event);
	void info(LogEvent::ptr event);
	void warn(LogEvent::ptr event);
	void error(LogEvent::ptr event);
	void fatal(LogEvent::ptr event);
	
	void addAppender(LogAppender::ptr appender);
	void delAppender(LogAppender::ptr appender);
	void clearAppender();
	LogLevel::Level getLevel() const{return m_level;}
	void setLevel(LogLevel::Level val){m_level = val;}
	std::string getName() const { return m_name;}

	LogFormatter::ptr getFormatter();
	void setFormatter(LogFormatter::ptr val);
	void setFormatter(const std::string& pattern);

	std::string toYamlString();
private:
	std::string m_name;							//日志名称
	LogLevel::Level m_level; 					//	日志级别
	LogFormatter::ptr m_formatter;				//	默认的日志格式
	std::list<LogAppender::ptr> m_appenders;	//Appender集合
	Logger::ptr m_root;

	MutexType m_mutex;
};








//输出到控制台的Appender
class StdoutLogAppender : public LogAppender
{
public:
	typedef std::shared_ptr<StdoutLogAppender> ptr;
	void log(LogLevel::Level level, Logger::ptr logger, LogEvent::ptr event) override;

	std::string toYamlString();
};

//定义输出到文件的Appender
class FileLogAppender : public LogAppender
{
public:
	typedef std::shared_ptr<FileLogAppender> ptr;
	FileLogAppender(const std::string& filename);
	void log(LogLevel::Level level, Logger::ptr logger, LogEvent::ptr event) override;

	bool reopen();

	std::string toYamlString();
private:
	std::string m_name;
	std::ofstream m_filestream;

	uint64_t m_lastTime = 0;
};


// 日志器管理类
class LoggerManager
{
public:
	typedef Spinlock MutexType;
	LoggerManager();
	Logger::ptr getLogger(const std::string & name);

	void init();

	Logger::ptr getRoot() const {return m_root;}

	std::string toYamlString();
private:
	/// 日志器容器
    std::map<std::string, Logger::ptr> m_loggers;
    /// 主日志器
    Logger::ptr m_root;

	MutexType m_mutex;
};

typedef sylar::Singleton<LoggerManager> LoggerMgr;





};

#endif
